package view;

import generateConnections.*;
import generateNodes.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import analyze.AStarSearch;
import analyze.AnalyzeDisjointness;
import analyze.AnalyzeInfo;
import analyze.AnalyzeStatistics;

import logging.Logger;

import object.Node;
import util.ConnectionUtil;
import util.MappingUtil;
import util.NodeUtil;
import util.Settings;

public class View extends JFrame {
	private static final long serialVersionUID = 601015514766119511L;

	private int xSize;
	private int ySize;
	private GenerateNodeBase nodeGen;
	private GenerateConnectionBase connGen;
	JMenuBar menuBar;
	Map map;


	private ArrayList<Node> nodes;

	public View(final ArrayList<Node> nodesList) {
		this.nodes = nodesList;

		Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
		xSize = (int) bounds.getWidth();
		// xMid = xSize / 2;

		ySize = (int) bounds.getHeight();
		// yMid = ySize / 2;

		Logger.getInstance().log(Logger.TRACE, "View go");

		this.setTitle("Meshwork");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setMinimumSize(new Dimension(300,200));
		this.setExtendedState(JFrame.MAXIMIZED_BOTH);
		this.setLocationRelativeTo(null);

		createMenu();

		map = new Map(nodes);

		this.add(map, BorderLayout.CENTER);

		this.setVisible(true);
		Logger.getInstance().log(Logger.TRACE, "View Completed xSize: " + xSize + " YSize: " + ySize);
	}

	public void createMenu() {
		menuBar = new JMenuBar();
		// BEGIN FILE
		JMenu fileMenu = new JMenu("File");
		fileMenu.setMnemonic(KeyEvent.VK_F);

		JMenuItem exitMItem = new JMenuItem("Exit");
		exitMItem.setMnemonic(KeyEvent.VK_E);
		exitMItem.setToolTipText("Exit Application");
		exitMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.exit exit");
				System.exit(0);
			}
		});
		fileMenu.add(exitMItem);
		menuBar.add(fileMenu);
		// END FILE
		// BEGIN EDIT
		JMenu editMenu = new JMenu("Edit");
		editMenu.setMnemonic(KeyEvent.VK_E);
		menuBar.add(editMenu);

		JMenuItem clearMItem = new JMenuItem("Clear All");
		clearMItem.setMnemonic(KeyEvent.VK_C);
		clearMItem.setToolTipText("Clear Nodes and Connections");
		clearMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Clear Nodes and Connections");
				// garbage collection should take care of?
				nodes.clear();
				map.repaint();
			}
		});
		editMenu.add(clearMItem);

		JMenuItem clearConnMItem = new JMenuItem("Clear Connections");
		clearConnMItem.setMnemonic(KeyEvent.VK_L);
		clearConnMItem.setToolTipText("Clear Connections");
		clearConnMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Clear Connections");
				NodeUtil.removeAllConnections(nodes);
				NodeUtil.resetAllNodesColor(nodes);
				map.repaint();
			}
		});
		editMenu.add(clearConnMItem);

		JMenuItem resetColorMItem = new JMenuItem("Reset Colors");
		resetColorMItem.setMnemonic(KeyEvent.VK_R);
		resetColorMItem.setToolTipText("Reset all colors");
		resetColorMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Clear Connections");
				NodeUtil.resetAllNodesColor(nodes);
				ConnectionUtil.resetAllConnectionsColor(nodes);
				map.repaint();
			}
		});
		editMenu.add(resetColorMItem);

		JMenuItem settingMItem = new JMenuItem("Settings");
		settingMItem.setMnemonic(KeyEvent.VK_S);
		settingMItem.setToolTipText("Meshwork Settings");
		settingMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.settings settings");
				new SettingsPanel();
			}
		});
		editMenu.add(settingMItem);
		// END EDIT
		// BEGIN NODE
		JMenu nodeMenu = new JMenu("Node Algorithm");
		nodeMenu.setMnemonic(KeyEvent.VK_N);
		menuBar.add(nodeMenu);
		// BEGIN RANDOM
		JMenu randomMenu = new JMenu("Random");
		randomMenu.setMnemonic(KeyEvent.VK_R);
		nodeMenu.add(randomMenu);

		JMenuItem nodesMItem = new JMenuItem("Nodes");
		nodesMItem.setMnemonic(KeyEvent.VK_N);
		nodesMItem.setToolTipText("Generate Nodes");
		nodesMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Generate random Nodes");
				nodeGen = new GenerateRandomNodes();
				nodes.clear();
				map.repaint();
			}
		});
		randomMenu.add(nodesMItem);

		// END RANDOM
		//BEGIN CLUSTER
		JMenu clusterMenu = new JMenu("Cluster");
		clusterMenu.setMnemonic(KeyEvent.VK_C);
		nodeMenu.add(clusterMenu);

		JMenuItem clusterMItem = new JMenuItem("Cluster");
		clusterMItem.setMnemonic(KeyEvent.VK_C);
		clusterMItem.setToolTipText("Generate Nodes as clusters");
		clusterMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Generate clusters");
				nodeGen = new GenerateRandomClusters();
				nodes.clear();
				map.repaint();
			}
		});
		clusterMenu.add(clusterMItem);

		//END CLUSTER
		JMenuItem delNodeMItem = new JMenuItem("Delete Random Node");
		delNodeMItem.setMnemonic(KeyEvent.VK_D);
		delNodeMItem.setToolTipText("Delete Random Node");
		delNodeMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.del rand node");
				if(nodes.size() > 0){
					Random r = new Random();
					NodeUtil.removeNode(nodes.get(Math.abs(r.nextInt()%nodes.size())), nodes);
					MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
					map.repaint();
				}
			}
		});
		nodeMenu.add(delNodeMItem);
		// END NODE
		//BEGIN CONNECTION
		JMenu connMenu = new JMenu("Connection");
		connMenu.setMnemonic(KeyEvent.VK_C);
		menuBar.add(connMenu);
		// BEGIN RANDOM
		JMenu randomMenuConn = new JMenu("Random");
		randomMenuConn.setMnemonic(KeyEvent.VK_R);
		connMenu.add(randomMenuConn);

		JMenuItem connectionsMItem = new JMenuItem("Connections");
		connectionsMItem.setMnemonic(KeyEvent.VK_C);
		connectionsMItem.setToolTipText("Generate Connections");
		connectionsMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Generate random Connections");
				connGen = new GenerateRandomConnection();
				NodeUtil.removeAllConnections(nodes);
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();
			}
		});
		randomMenuConn.add(connectionsMItem);
		//BEGIN LARGE NETWORK
		//BEGIN RANGE
		JMenu rangeMenu = new JMenu("Range");
		rangeMenu.setMnemonic(KeyEvent.VK_N);
		connMenu.add(rangeMenu);

		JMenuItem shortMenuItem = new JMenuItem("Shortest");
		shortMenuItem.setMnemonic(KeyEvent.VK_S);
		shortMenuItem.setToolTipText("Generate Nodes based on shortest connection");
		shortMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				NodeUtil.removeAllConnections(nodes);
				Logger.getInstance().log(Logger.TRACE, "View.Generate shortest");
				connGen = new GenerateShortestConnection();
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();
			}
		});
		rangeMenu.add(shortMenuItem);
		
		JMenuItem longMItem = new JMenuItem("Longest");
		longMItem.setMnemonic(KeyEvent.VK_L);
		longMItem.setToolTipText("Generate Connections based off longest connections");
		longMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Generate longest Connections");
				connGen = new GenerateLongestConnection();
				NodeUtil.removeAllConnections(nodes);
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();
			}
		});
		rangeMenu.add(longMItem);
		//END RANGE
		

		JMenuItem largeMItem = new JMenuItem("Connect Networks");
		largeMItem.setMnemonic(KeyEvent.VK_K);
		largeMItem.setToolTipText("Connect Based on Current Connections");
		largeMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Connect Networks");
				connGen = new ConnectNetworks();
				NodeUtil.removeAllConnections(nodes);
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();

			}
		});
		connMenu.add(largeMItem);
		//END CONNECT NETWORK
		//START LARGE NETWORK
		JMenuItem largeNetMItem = new JMenuItem("Large Network");
		largeNetMItem.setMnemonic(KeyEvent.VK_L);
		largeNetMItem.setToolTipText("Each node will connect to the largest network in the area");
		largeNetMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.large network");
				connGen = new GenerateLargeNetwork();
				NodeUtil.removeAllConnections(nodes);
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();
			}
		});
		connMenu.add(largeNetMItem);
		
		//END LARGE NETWORK
		
		//START DYNAMIC NETWORK
		JMenuItem DynamicNetMItem = new JMenuItem("Dynamic Network");
		DynamicNetMItem.setMnemonic(KeyEvent.VK_L);
		DynamicNetMItem.setToolTipText("This schema uses network checking to create the largest possible network");
		DynamicNetMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.Dynamic network");
				connGen = new GenerateDynamicNetwork();
				NodeUtil.removeAllConnections(nodes);
				MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
				map.repaint();
			}
		});
		connMenu.add(DynamicNetMItem);
				
		//END DYNAMIC NETWORK
		
		//START LIMITED NETWORK
				JMenuItem LimitedMItem = new JMenuItem("Limited Network");
				LimitedMItem.setMnemonic(KeyEvent.VK_L);
				LimitedMItem.setToolTipText("This schema uses network checking to create the largest possible network");
				LimitedMItem.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent arg0) {
						Logger.getInstance().log(Logger.TRACE, "View.Limited network");
						connGen = new GenerateLimitedConnections();
						NodeUtil.removeAllConnections(nodes);
						MappingUtil.generateOneAtATime(nodes, Settings.getInstance().getNumNodes(), Settings.getInstance().getNumRandomConnections(), map.getWidth(), map.getHeight(), nodeGen, connGen);
						map.repaint();
					}
				});
				connMenu.add(LimitedMItem);
						
		//END LIMITED NETWORK
		
		//END CONNECTION
		// BEGIN ANALYZE
		JMenu analyzeMenu = new JMenu("Analyze");
		analyzeMenu.setMnemonic(KeyEvent.VK_A);

		JMenuItem disjointMItem = new JMenuItem("Disjointness");
		disjointMItem.setMnemonic(KeyEvent.VK_D);
		disjointMItem.setToolTipText("Show Disjoint Networks");
		disjointMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE,
						"View.AnalyzeDisjointness");
				AnalyzeDisjointness a = new AnalyzeDisjointness();
				ArrayList<AnalyzeInfo> results = a.Analyze(nodes);
				map.repaint();
				new ScrollableInfoPanel(results, "Network Stats");
			}
		});
		analyzeMenu.add(disjointMItem);


		JMenuItem netStatsMItem = new JMenuItem("Network Statistics");
		netStatsMItem.setMnemonic(KeyEvent.VK_S);
		netStatsMItem.setToolTipText("Display Statistics about Networks");
		netStatsMItem.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0){
				Logger.getInstance().log(Logger.TRACE, "View.NetworkStats");
				AnalyzeStatistics a = new AnalyzeStatistics();
				new ScrollableInfoPanel(a.Analyze(nodes), "Network Statistics");
			}
		});
		analyzeMenu.add(netStatsMItem);
		// END ANALYZE
		// START A*
		JMenuItem aStarMItem = new JMenuItem("A*");
		aStarMItem.setMnemonic(KeyEvent.VK_A);
		aStarMItem.setToolTipText("A Star Path finding");
		aStarMItem.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0){
				Logger.getInstance().log(Logger.TRACE, "View.A*");
				AStarSearch a = new AStarSearch();
				map.repaint();
				new ScrollableInfoPanel(a.Analyze(nodes), "A* Search");
			}
		});
		analyzeMenu.add(aStarMItem);
		menuBar.add(analyzeMenu);
		// END A*
		// BEGIN ABOUT
		JMenu aboutMenu = new JMenu("About");
		aboutMenu.setMnemonic(KeyEvent.VK_B);
		menuBar.add(aboutMenu);

		JMenuItem aboutMItem = new JMenuItem("About");
		aboutMItem.setMnemonic(KeyEvent.VK_A);
		aboutMItem.setToolTipText("About Meshwork");
		aboutMItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Logger.getInstance().log(Logger.TRACE, "View.about about");
				JOptionPane.showMessageDialog(new JFrame(), "A project to create, simulate, work with, and analyze Wireless Mesh Networking\nAuthors: Michael Kent, Dustin Stage\nhttp://code.google.com/p/meshnetworking/",  "Meshwork About", JOptionPane.PLAIN_MESSAGE);
			}
		});
		aboutMenu.add(aboutMItem);
		// END ABOUT
		setJMenuBar(menuBar);
	}

	public int getXSize() {
		return xSize;
	}

	public int getYSize() {
		return ySize;
	}

	public void setNodes(ArrayList<Node> nodes) {
		this.nodes = nodes;
	}

	public void repaintPoints() {
		map.repaint();
	}

}
